var defaultOpts = {
    needTools: true,
    mutilPage: true
};
/**
 * 富文本Class定义，
 * 封装富文本输入框事件、选区相关API
 * 定义extend注册函数，其他功能模块通过extend实现注册
 * by kevin.huang
 * ***/
class Keditor extends $B.BaseControl {
    constructor(elObj, opts) {
        super();
        this.DPI = UTILS.getDPI();
        console.log("dpi "+this.DPI);       
        this.opts = $B.extendObjectFn(true, {}, defaultOpts, opts);
        this.debug = this.opts.debug;
        super.setElObj(elObj);
        $B.DomUtils.addClass(this.elObj, "k_edit_main k_box_size");
        let contents = this.elObj.innerHTML;
        this.elObj.innerHTML = "";        
        this.$mainWrap = $B.DomUtils.createEl("<div  class='k_edit_input_wrap k_box_size' style='overflow: hidden; position: absolute; top: 0px; left: 0px; width: 100%; height: 100%;background:#F3F4F5;'></div>");
        var _this = this;
        this.colorIns = new $B.Color(undefined, {
            mouseleaveHide: true,
            onChange: function (hex, opacity) {
                if (_this.colorIns._callFnKey) {
                    let colorCallFN = "color_" + _this.colorIns._callFnKey;
                    if (_this[colorCallFN]) {
                        _this[colorCallFN].call(this, hex, opacity);
                    }
                }
            },
            onHideFn: function (ins) {
                _this.clearSelectionColor();            
            }
        });       
        if (this.opts.needTools) {
            this.toolIns = new KeditTools(this);
            let h = this.toolIns.getHeight() + 2;
            $B.DomUtils.css(this.$mainWrap, { "border-top": h + "px solid #fff" });
        }        
        let $pageEl = this.createDocPage(true);
        if (this.opts.mutilPage) {
            $B.Dom.css(this.$mainWrap, { "border-bottom": "32px solid #F3F4F5", "overflow": "auto"});
            this.initMutilPage($pageEl);
            setTimeout(()=>{
                this.insertPage();
                this.insertPage();
            },0);
            this.setInputElVar(this.$pageWap.firstChild);
        } else {
            $B.Dom.append(this.$mainWrap, $pageEl);
            this.$pageWap = $pageEl;
            this.setInputElVar(this.$pageWap);
        }       
        this.bindInputeEvents(this.$input);
        this.cssEls = [];//需要修饰的元素
        this.cssPEls = [];  //段落

        setTimeout(() => {
            this.bindFocusEv(this.colorIns.elObj);
        }, 10);        
        contents = this.clearHtmlStr(contents);
        if (contents !== "") {
            this.$input.innerHTML = contents;
        }
        $B.DomUtils.prepend(this.elObj, this.$mainWrap);

        $B.DomUtils.mouseup(document, (e) => {
            if (this.isUserMouseDown) {
                if (this.tableIns.isSelectedTds()) {
                    this.tableIns.cancelMutilSelect();
                } else {
                    this.mouseup(e);
                }
            }
        });
        this.tableIns = new Table(this);
        if (navigator.userAgent.indexOf("Firefox") > 0) {
            document.designMode = "on";
            document.execCommand('enableObjectResizing', false, 'false');
            document.designMode = "off";
        }

        var isReqFrame = false;
        var resizeEvent = () => {
            if (!isReqFrame) {
                isReqFrame = true;
                requestAnimationFrame(() => {
                    isReqFrame = false;
                    let headH;
                    if (this.opts.needTools) {
                        headH = this.toolIns.getHeight() + 2;
                        let old = parseFloat(this.$mainWrap.style.borderTopWidth.replace("px", ""));
                        if (headH !== old) {
                            $B.DomUtils.css(this.$mainWrap, { "border-top": headH + "px solid #fff" });
                        }
                    }
                    if (this.onResizingFn) {
                        this.onResizingFn(headH);
                    }
                });
            }
        };
        $B.DomUtils.resize(window, resizeEvent, 100);
        this.ResizeIns = new $B.Resize({
            target: undefined,
            dragStart: function (args) {
            },
            onDrag: function (args) {
                console.log("resizing ", args);
            },
            dragEnd: function (args) {
                console.log("resize end ", args);
            }
        });
        this.ResizeIns.setStyle({
            "background": "#0C9CE5",
            "width": 6,
            "height": 6
        }, {
            "border": "1px dashed #0C9CE5"
        });
        setTimeout(() => {
            this.URDOINS = new URDO(this);
        }, 10);
    }
    setInputElVar($pageEl){
        this.$input = this.getPageInputEl($pageEl); 
    }
    getPageInputEl($pageEl){
        if (this.opts.mutilPage) {//多页模式
            let $0 = this.getPageInputWrap($pageEl);
            return $B.Dom.children($0, "._input_field")[0];
        }
        return $B.Dom.children($pageEl, "._input_field")[0];
    }
    getPageInputWrap($pageEl){
        let $0 = $B.Dom.children($pageEl,".pg_input_wap")[0];
        return $0;
    }   
    getColorIns(eventKey, onChange) {
        let colorCallFN = "color_" + eventKey;
        this[colorCallFN] = onChange;
        return this.colorIns;
    }
    /**
     * 处理入口
     * fn：处理函数的名称，params参数，eventEl触发处理的元素
     * **/
    execute(fn, params, eventEl) {
        if (typeof this[fn] === "function") {
            let go = this.beforeExecute(fn, params, eventEl);
            if (go) {
                if (fn !== "paintBrushFn" && fn !== "clearFn" && fn !== "eraserFn" && fn !== "insertTableFn") {
                    this.makeUndoData(fn, params);
                }
                this[fn](params, eventEl);
                let timer = 1;
                if (fn === "backgroundColorFn" || fn === "fontColorFn" || fn === "pcolorFn" || fn === "pbackground") {
                    timer = 1000;
                }
                this.putUndoData(timer);
            }
            this.afterExecute(fn, params, eventEl);
        } else {
            if (fn === "undoFn" || fn === "redoFn") {
                this.URDOINS[fn]();//执行撤销回退
            }
        }
    }
    makeUndoData(fn, params) {
        this.URDOINS.makeUndo(fn, params);
    }
    putUndoData(time) {
        if (!time) {
            time = 1;
        }
        clearTimeout(this.putUndoTimer);
        this.putUndoTimer = setTimeout(() => {
            this.URDOINS.putCurUndo();
            this.URDOINS.clearRedoRec();
            this.clearUndoingData();
        }, time);
    }
    /**
     * isForce是否强制生成一个新的undo记录
     * **/
    makePutUndoImd(isForce) {
        if (isForce) {
            this.clearUndoingData();
        }
        this.makeUndoData();
        this.putUndoData(1);
    }
    clearUndoingData() {
        this.URDOINS.undoData = undefined;
    }
    /**
     * 绑定输入域事件
     * **/
    bindInputeEvents($input) {
        if (!this.inputEvents) {
            this.inputEvents = {
                mousedown: (e) => {
                    UTILS.stopDefaultctxMenu();
                    let r = this.mousedown(e);
                    if (typeof r !== "undefined") {
                        return r;
                    }
                },
                mouseup: (e) => {
                    if (this.tableIns.isSelectedTds()) {
                        this.tableIns.cancelMutilSelect();
                    } else {
                        let r = this.mouseup(e);
                        if (typeof r !== "undefined") {
                            return r;
                        }
                    }
                },
                keydown: (e) => {
                    let r = this.keydown(e);
                    if (typeof r !== "undefined") {
                        return r;
                    }
                },
                keyup: (e) => {
                    let r = this.keyup(e);
                    if (typeof r !== "undefined") {
                        return r;
                    }
                },
                mouseleave: (e) => {
                    this.mouseleave(e);
                },
                paste: (e) => {
                    this.paste(e);
                    if (typeof r !== "undefined") {
                        return r;
                    }
                },
                focus: (e) => {
                    if (this.tableIns.isSelectedTds()) {
                        let el = e.target;
                        this._fixFocusOnMonseEvent(el);
                    }
                }
            };
        }
        $B.DomUtils.bind($input, this.inputEvents);
        if (!this.wrapEvents) {
            this.wrapEvents = {
                mousemove: (e) => {
                    if (this.BrushingCSS) {
                        this.brushingMoving(e);
                    }
                }
            };
        }
        if (!this.scrollListner) {
            let isReqFrame = false;
            this.scrollListner = (e) => {
                if (!isReqFrame) {
                    isReqFrame = true;
                    let el = e.target;
                    requestAnimationFrame(() => {
                        if (!this._scringprs) {
                            this._scringprs = {
                                top: el.scrollTop,
                                left: el.scrollLeft
                            };
                        }
                        let diff1 = Math.abs(el.scrollTop - this._scringprs.top);
                        let diff2 = Math.abs(el.scrollLeft - this._scringprs.left);
                        if (diff1 > 5 || diff2 > 5) {
                            this.hidePanel();
                        }
                        this._scringClrTimer = setTimeout(() => {
                            this._scringprs = undefined;
                        }, 800);
                        if (this.onScrolling) {
                            this.onScrolling(e)
                        }
                        isReqFrame = false;
                    });
                }
            };
        }
        if (this.opts.mutilPage) {
            $B.DomUtils.scroll(this.$pageWap, this.scrollListner);
        } else {
            this.wrapEvents["scroll"] = this.scrollListner;
        }
        $B.DomUtils.bind($input.parentNode, this.wrapEvents);
    }
    /**
     * 按下键处理，对delete事件做删除前处理，防止出现空标签，无span标签场景
     * 对回车事件做处理，修正浏览器默认处理
     * **/
    keydown(e) {
        if (e.keyCode === 9) {
            this.isTabkey = true;
            clearTimeout(this._tabkeyTimer);
            this._tabkeyTimer = setTimeout(() => {
                this.isTabkey = undefined;
            }, 500);
            return false;
        }
        var isDeleted = e.keyCode === 8 || e.keyCode === 46;
        if (isDeleted) {
            //提取在删除区域内的td元素，为td元素做修复处理
            let focusEl = this._getDomRange(true);//先获取当前鼠标所在的元素           
            let isOnlyEl = !focusEl.nextSibling && !focusEl.previousSibling;
            if (isOnlyEl) { //只有一个元素
                let $pel = this._getPelByChild(focusEl);
                if (!$pel.previousSibling) {
                    if (focusEl.innerText === "\u200B") { //第一行不允许删除
                        return false;
                    }
                }
            }
            this.focusPElement = this._getPelByChild(focusEl);//当前focus段落
            this.makeUndoData();
            this.putUndoData(666);
        } else if (e.keyCode === 13) {//回车
            this.focusElement = this._getDomRange(true);//先获取当前鼠标所在的元素 
            if (!this.enterKeyDownp) {
                this.enterKeyDownp = this._getPelByChild(this.focusElement);
            }
            this.listStyle = this.anyliscList(this.focusElement);
        }
    }
    /**
     * 放开按键处理
     * **/
    keyup(e) {
        if (this.isTabkey) {
            this.convertTabKey(e);
            return false;
        }
        clearTimeout(this._savingRegionTimer);
        this._savingRegionTimer = setTimeout(() => {
            this.saveRegion();
        }, 500);
        //确保光标不在\u200b前面  
        if (e.keyCode >= 37 && e.keyCode <= 40) {
            this.checkCursorPos();
            return true;
        }
        var isDeleted = e.keyCode === 8 || e.keyCode === 46;
        let goCheckSeq = true;
        if (isDeleted) {
            if (this.focusPElement) {
                if (this.focusPElement.firstChild.tagName === "BR") {
                    if (this.focusPElement.previousSibling) {
                        this.move2end(this.focusPElement.previousSibling);
                        $B.DomUtils.remove(this.focusPElement);
                    } else {
                        let $br = this.focusPElement.firstChild;
                        let $span = this.createSpanEl();
                        $B.DomUtils.append(this.focusPElement, $span);
                        this.focusPElement.removeChild($br);
                        this.move2end($span);
                    }
                }
                this.focusPElement = undefined;
            }
        } else if (e.keyCode === 13) {//回车
            goCheckSeq = false;
            this.onEnterAfter(e);
        }
        if (goCheckSeq) {
            this.keyupSEQ(e, isDeleted);
        }

    }
    checkCursorPos() {
        console.log("checkCursorPos>>>");
        clearTimeout(this.checkCursorTimer);
        this.checkCursorTimer = setTimeout(() => {
            let rgi = this._getDomRange();
            let start = rgi.startOffset;
            let txtNode = rgi.endContainer;
            let txt = txtNode.nodeValue;
            if (txt[0] === "\u200b" && start === 0) {
                this.setRegion(txtNode, txtNode, 1, 1);
                this.saveRegion();
            }
        }, 222);
    }
    keyupSEQ(e, isDeleted) {
        clearTimeout(this.keyupSEQTimer);
        this.keyupSEQTimer = setTimeout(() => {
            if (isDeleted) {
                let focusEl = this._getDomRange(true);
                let focusPElement = this._getPelByChild(focusEl);//当前focus段落
                let math = this.anyliscList(focusPElement);
                if (math) {
                    math.usePrs = true;
                    this.updateListSeq(focusPElement.nextSibling, math);
                }
            }
        }, 500);
    }
    convertTabKey(e) {
        let rgi = this._getDomRange();
        if (rgi.collapsed) {
            let txtNode = rgi.endContainer;
            let $prt = txtNode.parentNode;
            let start = rgi.startOffset;
            if (e.shiftKey && start === 0) {
                return;
            }
            start = this.addTabspace(txtNode, start, $prt, e.shiftKey);
            this.setRegion($prt.firstChild, $prt.firstChild, start, start);
            this.saveRegion();
        } else { //批量划选
            if (this.cssPEls.length === 0) {
                this.getCssEls(true);
            }
            this.loopPelCssEls(($p) => {
                let $s = $p.firstChild;
                if ($s.nodeName === "SPAN") {
                    if (!$B.Dom.attr($s, "contenteditable")) {
                        console.log($s, $s.innerHTML);
                        this.addTabspace($s.firstChild, 0, $s, e.shiftKey);
                    }
                }
            });
        }
    }
    addTabspace(txtNode, start, $prt, shiftKey) {
        let txt = txtNode.nodeValue;
        let news = [];
        if (shiftKey) {
            news = Array.from(txt);
            let i = 0;
            let shiftCount = 0;
            while (true) {
                if (news.length > 0) {
                    if (news[0] === "\u200b") {
                        if (news.length > 1) {
                            news[0] = news[1];
                            news[1] = "\u200b";
                        }
                    }
                    if (/\s/.test(news[0])) {
                        news.shift();
                        shiftCount++;
                    }
                }
                i++;
                if (i > 4 || shiftCount == 2) {
                    break;
                }
            }
            start = start - shiftCount;
            if (start < 0) {
                start = 0;
            }
        } else {
            if (start === 0 || (txt[0] === "\u200b" && start === 1)) {
                news.push("&nbsp;&nbsp;");
                news.push(txt);
            } else if (start === txt.length) {
                news.push(txt);
                news.push("&nbsp;&nbsp;");
            } else {
                for (let i = 0; i < txt.length; i++) {
                    news.push(txt[i]);
                    if ((i + 1) === start) {
                        news.push("&nbsp;&nbsp;");
                    }
                }
            }
            start = start + 2;
        }
        let newTxt = news.join("");
        if (newTxt === "") {
            newTxt = "\u200b";
        }
        $prt.innerHTML = newTxt;
        return start;
    }
    /**
    * 回车处理
    * ***/
    onEnterAfter(e) {
        var $startP = this.enterKeyDownp;
        this.enterKeyDownp = undefined;
        var ancEl = this.getFocusEle();
        var $up = ancEl.parentNode;
        var $p = $startP.nextSibling;
        let plist = [];
        while ($p) {
            let id = $B.generateDateUUID();
            $p.id = id;
            UTILS.removeBr($p);
            let childs = $p.children;
            if (childs.length > 0) {
                for (let i = 0; i < childs.length; i++) {
                    UTILS.removeBr(childs[i]);
                    if (childs[i].children.length === 0 && childs[i].innerText === "") {
                        childs[i].innerText = "\u200b";
                    }
                    this.loopUpdateId(childs[i]);
                }
            } else {
                $B.Dom.append($p, UTILS.createSpanEl());
            }
            plist.push($p);
            if ($p === $up) {
                break;
            }
            $p = $p.nextSibling;
        }
        if (this.listStyle) {
            let listStyle = this.listStyle;
            this.listStyle = undefined;
            //格式化一下序列           
            if (listStyle.idxText) {
                let $prep = listStyle.prePel;
                let $s = $prep.firstChild;
                let txt = $s.innerText.replaceAll("\u200b", "");
                txt = txt.replace(listStyle.idxText, "\u200b");
                $s.innerText = txt;
                $s = UTILS.createSpanEl();
                $s.innerText = "\u200b" + listStyle.idxText;
                $B.Dom.prepend(listStyle.prePel, $s);
            }
            //新行序列
            let mats = listStyle.nextIdx.match(/\d+/);
            let idx = parseInt(mats[0]);
            for (let i = 0; i < plist.length; i++) {
                $p = plist[i];
                let $s = UTILS.createSpanEl();
                $s.innerText = "\u200b" + listStyle.nextIdx.replace(/\d+/, idx);
                $B.Dom.prepend($p, $s);
                idx++;
            }
            if ($p.nextSibling) {
                this.updateListSeq($p.nextSibling, listStyle);
            }
        }
        this.focusElement = undefined;
        this.move2end($p);
        this.saveRegion();
    }
    /**
     * 清空划选的元素
     * **/
    clearCssEls() {
        this.cssEls = [];
        this.cssPEls = [];
    }
    _fixFocusOnMonseEvent(el) {
        let isRoot = $B.DomUtils.hasClass(el, "k_edit_input");
        if (isRoot) {
            el = el.lastChild;
        }
        if ($B.DomUtils.hasClass(el, "p_element")) { //嵌套表格所在行
            //console.log("on mouse down focus p");
            if (el.firstChild.nodeName === "TABLE") {
                this.skipMouseUP = true;
                setTimeout(() => {
                    this.skipMouseUP = undefined;
                    if (this.tableIns.isSelectedTds()) {//不需要focus元素
                        this.clearDomSelected();
                    } else {
                        this.tableIns.focusTable(el.firstChild);
                        this.reactiveTools();
                    }
                }, 1);
                return;
            } else if (isRoot) {
                this.skipMouseUP = true;
                setTimeout(() => {
                    this.skipMouseUP = undefined;
                    this.move2end(el.lastChild);
                    this.reactiveTools();
                }, 1);
                return;
            } else {
                this.move2end(el.lastChild);
            }
        }
    }
    isLinkAEl(el) {
        let isLinkClick = false;
        if (el.nodeName === "A") {
            isLinkClick = true;
        } else if ($B.Dom.hasClass(el, "_hyper_link")) {
            isLinkClick = true;
        }
        return isLinkClick;
    }
    isImgEl(el) {
        let ret = false;
        if (el.nodeName === "IMG") {
            ret = true;
        } else if ($B.Dom.hasClass(el, "_img_link")) {
            ret = true;
        }
        return ret;
    }
    hideAll() {
        this.ResizeIns.unbind();
        this.hidePanel();
        this.hidenLinkMenu();
        this.hideCtxMenu();
        this.hidenImgMenu();
    }
    /**
     * 按下鼠标左键处理，触发工具栏的监听
     * **/
    mousedown(e) {
        let el = e.target;
        this.hideAll();
        //多页开存在这个功能
        if (this.onClickActivedFN) {
            this.onClickActivedFN(e);
        }
        let go = !this.isLinkAEl(el);
        if (go) {
            go = !this.isImgEl(el);
        } else {
            return false;
        }
        if (go) {
            //如果是表格内点击则不触发clearSelected
            let isTableFrire = false;
            this._fixFocusOnMonseEvent(el);
            let helper = 0;
            while (helper <= 6 && el) {
                if (el.nodeName === "TD") {
                    isTableFrire = true;
                    break;
                }
                el = el.parentNode;
                helper++;
            }
            if (!isTableFrire) {
                this.tableIns.clearSelected(true);
            }
            this.unactivedLinePELS();
            this.clearCssEls();
            this.isUserMouseDown = true;
            if (this.toolIns && typeof this.toolIns.onEditorMouseDown === "function") {
                setTimeout(() => {
                    this.toolIns.onEditorMouseDown();
                }, 1);
            }
            this.isTableFrire = isTableFrire;
            setTimeout(() => {
                this.isTableFrire = undefined;
            }, 500);
        }
    }
    /**
     * 放开按键处理
     * **/
    mouseup(e) {
        if (this.BrushingCSS) {
            this.exeBrushing2el(this.BrushingCSS);
        }
        this.callOffBrush();
        let el = e.target;
        let skip = this.isLinkAEl(el);
        if (skip) {
            this.setRegionByEl(el);
            //弹出链接对话框
            this.showLinkMenu(el);
            return false;
        }
        skip = this.isImgEl(el);
        if (skip) {
            this.showImgMenu(el, e);
            return false;
        }
        if (!skip) {
            if (!e._e._skipDefault && !this.tableIns.dragging) {
                this.isUserMouseDown = false;
                if ($B.DomUtils.hasClass(e.target, "k_edit_td_wap")) {
                    this.move2end(e.target.firstChild.firstChild);
                } else {
                    this.saveRegion();
                }
                setTimeout(() => {
                    this.reactiveTools();
                }, 1);
                if (e.which === 3 && !this.isTableFrire) {
                    this.showCtxMenu({ left: e.pageX + 5, top: e.pageY + 10 });
                }
            }
        }
    }
    brushingMoving(e) {
        if (!this.$movingBrushMouseEl) {
            this.$movingBrushMouseEl = $B.Dom.createEl('<div style=cursor:pointer;position:absolute;width:16px;height:16px;display:none;"><i class="fa fa-brush" style="color:#34B72C;font-size:12px"></i></div>');
            $B.Dom.append(document.body, this.$movingBrushMouseEl);
        }
        this.$movingBrushMouseEl.style.display = "";
        this.$movingBrushMouseEl.style.top = (e.pageY + 3) + "px";
        this.$movingBrushMouseEl.style.left = e.pageX + "px";
    }
    reactiveTools(cssMap) {
        if (this.toolIns && this.toolIns.reactiveUI) {
            if (!cssMap) {
                cssMap = this.extractCss();
            }
            this.toolIns.reactiveUI(cssMap);
        }
    }
    mouseleave(e) {
        //console.log(">>>>>>>>>>",e);
    }
    paste(e) {

    }
    scroll(e) {
        this.hidePanel();
    }
    hidePanel() {
        this.tableIns.hidePanel();
        if (this.toolIns) {
            this.toolIns.hidePanel();
        }
        this.hideCtxMenu();
    }
    /**
     * 绑定鼠标focus事件
     * **/
    bindFocusEv($el) {
        if ($el.tagName !== "IFRAME") {
            if (!this.onFocusFn) {
                this.onFocusFn = (e) => {
                    this.rebuildRegion();
                    return false;
                };
            }
            $B.DomUtils.attribute($el, { "tabindex": "0" });
            $B.DomUtils.focus($el, this.onFocusFn);
            let childs = $el.children;
            for (let i = 0; i < childs.length; i++) {
                this.bindFocusEv(childs[i]);
            }
        }
    }
    /**
     * 获取焦点所在元素
     * isPel是否获取到段落元素
     * **/
    getFocusEle(isPel) {
        var selection = this._getSelection();
        if (selection) {
            var ancNode = selection.anchorNode;
            if (ancNode.nodeType === 3) {
                ancNode = ancNode.parentNode;
            }
            if (!$B.DomUtils.hasClass(ancNode, "p_span")) {
                return;
            }
            if (isPel) {
                while (ancNode) {
                    if ($B.DomUtils.hasClass(ancNode, "p_element")) {
                        break;
                    }
                    ancNode = ancNode.parentNode;
                }
            }
            return ancNode;
        }
    }
    /**
     * 获取dom region
     * forFocusEl是否获取鼠标所在元素
     * **/
    _getDomRange(forFocusEl) {
        var selection = this._getSelection();
        var region = selection.getRangeAt(0);
        if (forFocusEl) {
            let container = region.commonAncestorContainer;
            if (!region.collapsed) {
                container = region.startContainer;
            }
            if (container.nodeType === 1) {
                return container;
            }
            return container.parentNode;
        }
        return region;
    }
    /**
     * 获取选区信息
     * needEl是否需要保存对应的dom元素，否则只保存id
     * **/
    getRegion(needEl) {
        var region = this._getDomRange();
        var scontainer = region.startContainer;
        var econtainer = region.endContainer;
        //修正当前focus不是在可编辑区域的场景
        if (scontainer.nodeType === 1 && econtainer.nodeType === 1 && $B.Dom.hasClass(scontainer, "_e_btn_")) {
            let $firstEl = this.$input.firstChild;
            this.move2start($firstEl);
            region = this._getDomRange();
            scontainer = region.startContainer;
            econtainer = region.endContainer;
        }
        var startOfs = region.startOffset;
        var endOfs = region.endOffset;
        if (scontainer.nodeType === 1) {
            scontainer = scontainer.firstChild;
            startOfs = 0;
        }
        if (econtainer.nodeType === 1) {
            econtainer = econtainer.firstChild;
            endOfs = econtainer.innerText.length;
        }
        var $s, $e, $sp, $ep, $p, dirStrtId, dirEndId, isCollapsed = region.collapsed;
        if (isCollapsed) { //无选区
            $s = scontainer.parentNode;
            $e = $s;
            $p = this._getPelByChild($e);
            dirStrtId = $p.id;
            dirEndId = dirStrtId;
            $p = this._getRootPel($p);
            $sp = $p;
            $ep = $p;
        } else {//有选区
            $s = scontainer.parentNode;
            $sp = this._getPelByChild($s);
            dirStrtId = $sp.id;
            $e = econtainer.parentNode;
            $ep = this._getPelByChild($e);
            dirEndId = $ep.id;
            $sp = this._getRootPel($sp);
            $ep = this._getRootPel($ep);
        }
        //确保是跟段落
        var rgObj = {
            isCollapsed: isCollapsed,
            startPel: $sp.id,
            endPel: $ep.id,
            startSpan: $s.id,
            endSpan: $e.id,
            startIdx: startOfs,
            endIdx: endOfs,
            dirStrtId: dirStrtId,
            dirEndId: dirEndId
        };
        //console.log($s,$e,$sp,$ep);
        if (needEl) {
            rgObj["$startPel"] = $sp;
            rgObj["$endPel"] = $ep;
            rgObj["$startSpan"] = $s;
            rgObj["$endSpan"] = $e;
        }
        return rgObj;
    }
    _getSelection() {
        var selection;
        if (window.getSelection) {
            selection = window.getSelection();
        } else if (document.selection) {
            selection = document.selection.createRange();
        }
        return selection;
    }
    /**
     * 获取元素$el所在的段落元素
     * @param {*} $s 
     * @returns 
     */
    _getPelByChild($s) {
        var $p = $s;
        while ($p) {
            if ($B.DomUtils.hasClass($p, "p_element")) {
                break;
            }
            $p = $p.parentNode;
        }
        return $p;
    }
    /**
     * 保存选区信息到region变量
     * @param {*} needEl 
     */
    saveRegion(needEl) {
        this.region = this.getRegion(needEl);
    }
    /***
     * 根据暂存的选区信息恢复选区
     */
    rebuildRegion(r) {
        if (r) {
            this.region = r;
        }
        let regn = this.region;
        if (regn) {
            let startPel = regn.startPel;
            let endPel = regn.endPel;
            let startSpan = regn.startSpan;
            let endSpan = regn.endSpan;
            let startIdx = regn.startIdx;
            let endIdx = regn.endIdx;
            let $startP = $B.DomUtils.findbyId(this.$pageWap, startPel);
            if ($startP) {
                let $endP;
                if (startPel === endPel) {
                    $endP = $startP;
                } else {
                    $endP = $B.DomUtils.findbyId(this.$pageWap, endPel);
                }
                let firstEl = $B.DomUtils.findbyId($startP, startSpan);
                let endEl = $B.DomUtils.findbyId($endP, endSpan);
                this.setRegion(firstEl, endEl, startIdx, endIdx);
            }
        }
    }
    /**
     * 移动到 el元素尾部 
     */
    move2end(el) {
        if (!$B.DomUtils.hasClass(el, "p_span")) {
            el = el.lastChild;
            while (el) {
                if ($B.DomUtils.hasClass(el, "p_span")) {
                    break;
                }
                el = el.lastChild;
            }
        }
        el.focus();
        this.setRegionByEl(el, undefined, 1);
    }
    /**
     * 移动到 el元素头部
     */
    move2start(el) {
        if (!$B.DomUtils.hasClass(el, "p_span")) {
            el = el.firstChild;
            while (el) {
                if ($B.DomUtils.hasClass(el, "p_span")) {
                    break;
                }
                el = el.firstChild;
            }
        }
        this.setRegionByEl(el, undefined, 2);
    }
    /**
     * 根据dom元素设置选区
     * @param {*} startEl 元素
     * @param {*} endEl   元素
     * @param {*} flag 1移动到光标结束位置，2移动光标到开始位置
     */
    setRegionByEl(startEl, endEl, flag) {
        if (typeof endEl === "undefined") {
            endEl = startEl;
        }
        var firstChild = startEl.firstChild,
            lastChild = endEl.firstChild,
            startOffset = 0,
            endOffset = lastChild.length;
        if (flag) {
            if (flag === 1) {
                startOffset = endOffset;
            } else {
                if (firstChild.nodeValue[0] === "\u200b") {
                    startOffset = 1;
                }
                endOffset = startOffset;
            }
        }
        this.setRegion(firstChild, lastChild, startOffset, endOffset);
        this.saveRegion();
    }
    /**
     * 设置选区，元素是文本类型，指定开始，结束下标
     * **/
    setRegion(firstChild, lastChild, startOffset, endOffset) {
        if (firstChild.nodeType === 1) {
            firstChild = firstChild.firstChild;
        }
        if (lastChild.nodeType === 1) {
            lastChild = lastChild.firstChild;
        }
        var range = document.createRange();
        range.setStart(firstChild, startOffset);
        range.setEnd(lastChild, endOffset);
        var sel = window.getSelection();
        try {
            sel.removeAllRanges();
        } catch (ex) { }
        sel.addRange(range);
    }
    clearDomSelected() {
        $B.clearDomSelected();
        this.clearCssEls();
        this.region = undefined;
    }
    isSelected() {
        let r = this._getDomRange();
        return !r.collapsed;
    }
    /**
     * 是否存在选区
     * ***/
    hasRegion() {
        let r = this._getDomRange();
        return !r.collapsed;
    }
    /**
     * 是否已经聚焦fous
     * **/
    hasFocus() {
        let r = this._getDomRange();
        let container = r.commonAncestorContainer;
        if (container.nodeType === 3) {
            if ($B.Dom.hasClass(container.parentNode, "p_span")) {
                return true;
            }
        } else {
            if ($B.Dom.hasClass(container, "_input_field") || $B.Dom.hasClass(container, "p_element")) {
                return true;
            }
        }
    }
    destroy() {
        this.URDOINS.destroy();
        this.tableIns.destroy();
        this.ResizeIns.destroy();
        this.URDOINS = undefined;
        this.toolIns = undefined;
        this.tableIns = undefined;
        this.ResizeIns = undefined;
        super.destroy();
    }
}
Keditor.extend = function (obj) {
    Object.assign(this.prototype, obj);
};
$B["Keditor"] = Keditor;